using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace TemplateHelper
{
    public class TypeCollection : IEnumerable<TypeDeclaration>
    {
        private readonly List<TypeDeclaration> _types;

        public TypeCollection(IEnumerable<TypeDeclaration> types)
        {
            _types = types.ToList();
        }

        public static TypeCollection Inputs(int numberOfInputs)
        {
            var inputs = Enumerable.Range(1, numberOfInputs)
                .Select(nr => new InputTypedeclaration(nr));

            return new TypeCollection(inputs);
        }

        public static TypeCollection Inputs(int numberOfInputs, TypeDeclaration outputType)
        {
            var inputs = Enumerable.Range(1, numberOfInputs)
                .Select(nr => new InputTypedeclaration(nr));

            return new TypeCollection(inputs.Concat(new[] {outputType}));
        }        

        public TypeCollection Append(IEnumerable<TypeDeclaration> typeDeclarations)
        {
            var newTypes = new List<TypeDeclaration>(_types.Concat(typeDeclarations));
            return new TypeCollection(newTypes);
        }

        public TypeCollection Append(TypeDeclaration typeDeclaration)
        {
            return Append(new[] {typeDeclaration});            
        }

        public TypeCollection Append(params string[] typeNames)
        {
            var types = typeNames.Select(TypeDeclaration.FromTypeName);                
            return Append(types);
        }

        public string TypeDefinition()
        {
            return CreateDefinition();
        }

        public string CreateDefinition()
        {
            return $"<{string.Join(", ", _types.Select(type => type.TypeName))}>";
        }

        public string CreateDefinition(params string[] additionalTypeNames)
        {
            var additionalTypes = additionalTypeNames.Select(TypeDeclaration.FromTypeName);
            var augmentedCollection = Append(additionalTypes);
            return augmentedCollection.CreateDefinition();
        }

        public string JoinTypes(string separator)
        {
            return string.Join(separator, _types.Select(t => t.TypeName));
        }

        public string JoinArguments(string separator)
        {
            return string.Join(separator, _types.Select(t => t.ArgumentName));
        }

        public string Select(Func<TypeDeclaration, string> transform)
        {
            return Select(transform, Environment.NewLine);
        }

        public string Select(Func<TypeDeclaration, string> transform, string separator)
        {
            return string.Join(separator, _types.Select(transform));
        }

        public IEnumerator<TypeDeclaration> GetEnumerator()
        {
            return _types.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}